﻿using System;
using System.Collections.Generic;
using Al_FrameWork;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;


[CustomPropertyDrawer(typeof(Variable))]
public class VariableDrawer : PropertyDrawer
{
    private const float HORIZONTAL_GAP = 5;

    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        EditorGUI.BeginProperty(position, label, property);

        var name = property.FindPropertyRelative("name");
        var objectValue = property.FindPropertyRelative("objectValue");
        var dataValue = property.FindPropertyRelative("dataValue");
        var variableType = property.FindPropertyRelative("variableType");

        var y = position.y;
        var x = position.x;
        var height = GetPropertyHeight(property, label);
        var width = position.width - HORIZONTAL_GAP * 2;

        var nameRect = new Rect(x, y, Mathf.Min(200, width * 0.4f), height);
        var typeRect = new Rect(nameRect.xMax + HORIZONTAL_GAP, y, Mathf.Min(120, width * 0.2f), height);
        var valueRect = new Rect(typeRect.xMax + HORIZONTAL_GAP, y, position.xMax - typeRect.xMax - HORIZONTAL_GAP,
            height);

        EditorGUI.PropertyField(nameRect, name, GUIContent.none);

        var variableTypeValue = (VariableType)variableType.enumValueIndex;

        if (variableTypeValue == VariableType.Component)
        {
            var index = 0;
            var types = new List<Type>();
            var component = (Component)objectValue.objectReferenceValue;
            if (component != null)
            {
                var go = component.gameObject;
                foreach (var c in go.GetComponents<Component>())
                    if (c != null)
                        if (!types.Contains(c.GetType()))
                            types.Add(c.GetType());

                for (var i = 0; i < types.Count; i++)
                    if (component.GetType().Equals(types[i]))
                    {
                        index = i;
                        break;
                    }
            }

            if (types.Count <= 0)
                types.Add(typeof(Transform));

            var contents = new List<GUIContent>();
            foreach (var t in types) contents.Add(new GUIContent(t.Name, t.FullName));

            EditorGUI.BeginChangeCheck();
            var newIndex = EditorGUI.Popup(typeRect, GUIContent.none, index, contents.ToArray(),
                EditorStyles.popup);
            if (EditorGUI.EndChangeCheck())
            {
                if (component != null)
                    objectValue.objectReferenceValue = component.gameObject.GetComponent(types[newIndex]);
                else
                    objectValue.objectReferenceValue = null;
            }
        }
        else
        {
            EditorGUI.LabelField(typeRect, variableTypeValue.ToString());
        }

        switch (variableTypeValue)
        {
            case VariableType.Component:
                EditorGUI.BeginChangeCheck();
                objectValue.objectReferenceValue = EditorGUI.ObjectField(valueRect, GUIContent.none,
                    objectValue.objectReferenceValue, typeof(Component), true);
                if (EditorGUI.EndChangeCheck())
                    if (string.IsNullOrEmpty(name.stringValue) && objectValue.objectReferenceValue != null)
                        name.stringValue = NormalizeName(objectValue.objectReferenceValue.name);
                break;
            case VariableType.GameObject:
                EditorGUI.BeginChangeCheck();
                objectValue.objectReferenceValue = EditorGUI.ObjectField(valueRect, GUIContent.none,
                    objectValue.objectReferenceValue, typeof(GameObject), true);
                if (EditorGUI.EndChangeCheck())
                    if (string.IsNullOrEmpty(name.stringValue) && objectValue.objectReferenceValue != null)
                        name.stringValue = NormalizeName(objectValue.objectReferenceValue.name);
                break;
            case VariableType.Object:
                EditorGUI.BeginChangeCheck();
                objectValue.objectReferenceValue = EditorGUI.ObjectField(valueRect, GUIContent.none,
                    objectValue.objectReferenceValue, typeof(Object), true);
                if (EditorGUI.EndChangeCheck())
                    if (string.IsNullOrEmpty(name.stringValue) && objectValue.objectReferenceValue != null)
                        name.stringValue = NormalizeName(objectValue.objectReferenceValue.name);
                break;
            case VariableType.Color:
                var color = DataConverter.ToColor(dataValue.stringValue);
                EditorGUI.BeginChangeCheck();
                color = EditorGUI.ColorField(valueRect, GUIContent.none, color);
                if (EditorGUI.EndChangeCheck()) dataValue.stringValue = DataConverter.GetString(color);
                break;
            case VariableType.Vector2:
                var vector2 = DataConverter.ToVector2(dataValue.stringValue);
                EditorGUI.BeginChangeCheck();
                vector2 = EditorGUI.Vector2Field(valueRect, GUIContent.none, vector2);
                if (EditorGUI.EndChangeCheck()) dataValue.stringValue = DataConverter.GetString(vector2);
                break;
            case VariableType.Vector3:
                var vector3 = DataConverter.ToVector3(dataValue.stringValue);
                EditorGUI.BeginChangeCheck();
                vector3 = EditorGUI.Vector3Field(valueRect, GUIContent.none, vector3);
                if (EditorGUI.EndChangeCheck()) dataValue.stringValue = DataConverter.GetString(vector3);
                break;
            case VariableType.Vector4:
                var vector4 = DataConverter.ToVector4(dataValue.stringValue);
                EditorGUI.BeginChangeCheck();
#if UNITY_5_6_OR_NEWER
                vector4 = EditorGUI.Vector4Field(valueRect, GUIContent.none, vector4);
#else
                    var tmpRect = valueRect;
                    tmpRect.y -= height;
                    vector4 = EditorGUI.Vector4Field(tmpRect, "", vector4);
#endif
                if (EditorGUI.EndChangeCheck()) dataValue.stringValue = DataConverter.GetString(vector4);
                break;
            case VariableType.Boolean:
                var b = DataConverter.ToBoolean(dataValue.stringValue);
                EditorGUI.BeginChangeCheck();
                b = EditorGUI.Toggle(valueRect, GUIContent.none, b);
                if (EditorGUI.EndChangeCheck()) dataValue.stringValue = DataConverter.GetString(b);
                break;
            case VariableType.Float:
                var f = DataConverter.ToSingle(dataValue.stringValue);
                EditorGUI.BeginChangeCheck();
                f = EditorGUI.FloatField(valueRect, GUIContent.none, f);
                if (EditorGUI.EndChangeCheck()) dataValue.stringValue = DataConverter.GetString(f);
                break;
            case VariableType.Integer:
                var i = DataConverter.ToInt32(dataValue.stringValue);
                EditorGUI.BeginChangeCheck();
                i = EditorGUI.IntField(valueRect, GUIContent.none, i);
                if (EditorGUI.EndChangeCheck()) dataValue.stringValue = DataConverter.GetString(i);
                break;
            case VariableType.String:
                var s = DataConverter.ToString(dataValue.stringValue);
                EditorGUI.BeginChangeCheck();
                s = EditorGUI.TextField(valueRect, GUIContent.none, s);
                if (EditorGUI.EndChangeCheck()) dataValue.stringValue = DataConverter.GetString(s);
                break;
        }

        EditorGUI.EndProperty();
    }


    protected virtual string NormalizeName(string name)
    {
        if (string.IsNullOrEmpty(name))
            return "";

        name = name.Replace(" ", "");
        return char.ToLower(name[0]) + name.Substring(1);
    }
}